using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;

namespace ReactiveCode
{
    using Expressions;

    public abstract class ReactiveHandle : IDisposable
    {
        IDisposable _callHandle;

        public ReactiveHost Host { get; private set; }

        public abstract bool Enabled { get; set; }

        internal ReactiveHandle(ReactiveHost host)
        {
            Contract.Requires(host != null);
            Host = host;
            _callHandle = host.AddHandle(this);
        }

        public virtual void Dispose()
        {
            _callHandle.Dispose();
        }

        public event EventHandler<ReactiveUnhandledExceptionEventArgs> UnhandledException;
        internal void OnError(ReactiveUnhandledExceptionEventArgs e)
        {
            var handler = UnhandledException;
            if (handler != null)
                handler(this, e);
            Host.OnError(e);
        }
    }

    public sealed class ReactiveHandle<T> : ReactiveHandle
    {
        internal RootExpression<T> Expression { get; private set; }
        public override bool Enabled
        {
            get { return Expression.Enabled; }
            set { Expression.Enabled = value; }
        }

        public ReactiveMethod<T> Method
        {
            get { return Expression.Callee; }
        }
        public IObservable<T> Value
        {
            get
            {
                return Method.ReturnValue;
            }
        }

        internal ReactiveHandle(ReactiveHost host, ReactiveMethodDefinition<T> method)
            :base(host)
        {
            Contract.Requires<ArgumentNullException>(method != null, "method");
            Expression = new RootExpression<T>(this, method);
        }
        public override void Dispose()
        {
            base.Dispose();
            Expression.Dispose();
        }
    }
}